<?php

declare(strict_types=1);

namespace Zyucv7\Core\View;

use Zyucv7\Core\View\ViewException;

/**
 * PHP 原生视图渲染引擎
 * 支持布局嵌套和数据传递
 */
class View
{
    /**
     * 视图文件路径
     * @var string
     */
    private $viewPath;

    /**
     * 布局文件路径
     * @var string|null
     */
    private $layoutPath;

    /**
     * 传递给视图的数据
     * @var array
     */
    private $data = [];

    /**
     * View 构造函数
     * @param string $viewPath 视图文件的绝对或相对路径
     */
    public function __construct(string $viewPath)
    {
        if (!file_exists($viewPath)) {
            throw ViewException::InvalidArgument("View file not found: {$viewPath}");
        }
        $this->viewPath = $viewPath;
    }

    /**
     * 设置单个数据
     * @param string $key 键名
     * @param mixed $value 值
     * @return $this
     */
    public function with(string $key, $value): self
    {
        $this->data[$key] = $value;
        return $this;
    }

    /**
     * 批量设置数据
     * @param array $data 数据数组
     * @return $this
     */
    public function withData(array $data): self
    {
        $this->data = array_merge($this->data, $data);
        return $this;
    }

    public function withLayout(string $layoutPath): self
    {
        if (!file_exists($layoutPath)) {
            throw ViewException::InvalidArgument("Layout file not found: {$layoutPath}");
        }
        $this->layoutPath = $layoutPath;
        return $this;
    }

    /**
     * 渲染视图并直接输出
     * @return string
     */
    public function render($name): string
    {
        $viewPath = $this->viewPath . '/' . $name . '.php';
        if (!file_exists($viewPath)) {
            throw ViewException::InvalidArgument("View file not found: {$viewPath}");
        }
        // 将数据从数组中提取到变量，以便在模板中使用
        ob_start();
        extract($this->data);
        if ($this->layoutPath) {
            // 1. 开启输出缓冲，捕获内容视图的输出
            ob_start();
            include $viewPath;
            // 2. 将捕获的内容存入 $content 变量
            $content = ob_get_clean();
            // 3. 包含布局文件，布局文件中可以访问 $content 变量
            include $this->layoutPath;
        } else {
            // 如果没有布局，直接包含视图文件
            include $viewPath;
        }

        return ob_get_clean();
    }
}
